package edu.gatech.cs2340.mule.model;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.Serializable;
import java.util.ArrayList;

import javax.swing.Timer;


/**
 * 
 * This class will keep track of the current player and how long
 * each player has for his or her turn.
 * 
 * @author Keegan Nesbitt
 *
 */
public class TurnEngine implements Serializable {
	
	private static final long serialVersionUID = 1104519910544533320L;
	
	private Timer turnTimer;
	private int timeLeft;
	private Player[] allPlayers;
	private int currentPlayerIndex;
	private int gameRound;
	private int passesPerRound;
	private boolean isNewRound;
	
	/**
	 * 
	 * Initializes the array of players and the Timer.
	 * Also contains the ActionListener for counting down the seconds 
	 * in the player's turn.
	 * 
	 * @param allPlayers All the players in the game
	 */
	public TurnEngine(Player[] allPlayers) {
		isNewRound = true;

		this.allPlayers = allPlayers;
		createTimer();
		
		turnTimer.setRepeats(true);
		currentPlayerIndex = 0;
		gameRound = 1;
	}
	
	/**
	 * Calculates the time a player will start with at the beginning
	 * of their turn
	 * 
	 * @param p the current player
	 * @return the amount of time the player will start with
	 */
	private int startingTime(Player p) {
		int round = getGameRound();
		
		if(round < 5) {
			if(p.getFoodAmount() > 2) {
				return 50;
			}
			else if(p.getFoodAmount() > 0) {
				return 30;
			}
			else {
				return 5;
			}
		}
		else if(round < 9) {
			if(p.getFoodAmount() > 3) {
				return 50;
			}
			else if(p.getFoodAmount() > 0) {
				return 30;
			}
			else {
				return 5;
			}
		}
		else {
			if(p.getFoodAmount() > 4) {
				return 50;
			}
			else if(p.getFoodAmount() > 0) {
				return 30;
			}
			else {
				return 5;
			}
		}
	}
	
	/**
	 * Reorders the player array, arranging players by ascending score order
	 */
	public void calculatePlayerOrder() {
		
		//copy over list of players
		ArrayList<Player> temp = new ArrayList<>(allPlayers.length);
		for(int i = 0; i < allPlayers.length; i++) {
			temp.add(allPlayers[i]);
		}
		
		allPlayers = new Player[temp.size()];
		int i = 0;
		while(i < allPlayers.length) {
			int min = temp.get(0).calculatePlayerScore(); 
			Player minP = temp.get(0);
			int j = 0;
			Player p = temp.get(0);
			while(j < temp.size()) {
				p = temp.get(j);
				if(p.calculatePlayerScore() < min) {
					min = p.calculatePlayerScore();
					minP = p;
				}
				j++;
			}
			temp.remove(minP);
			allPlayers[i] = minP;
			i++;
		}
		
		//set the first player of the round to last place (for random events)
		for(int j = 0; j < allPlayers.length; j++) {
			if(j == 0) {
				allPlayers[j].setInLast(true); 
			}
			else {
				allPlayers[j].setInLast(false);
			}
		}
	}
	/**
	 * 
	 * Returns the current player
	 * 
	 * @return The current player
	 */
	public Player getCurrentPlayer() {
		return allPlayers[currentPlayerIndex];
	}
	
	/**
	 * 
	 * @return The current player's name
	 */
	public String getCurrentPlayerName() {
		return allPlayers[currentPlayerIndex].getPlayerName();
	}
	
	/**
	 * Returns the amount of time left in the current player's turn
	 * 
	 * @return The amount of time left in the current turn
	 */
	public int getTimeLeft() {
		return timeLeft;
	}
	
	/**
	 * Returns whether or not there is still time left in the current player's turn
	 * 
	 * @return True if the player has time left in his/her turn, false otherwise
	 */
	public boolean isTimeLeft() {
		return timeLeft > 0;
	}
	
	/**
	 * 
	 * Current round is not the actual round of the game. It is the number of times all
	 * players have had a turn.
	 */
	public void resetGameRound() {
		gameRound = 1;
	}
	
	/**
	 * 
	 * @return The current round of the game
	 */
	public int getGameRound() {
		return gameRound;
	}
	
	/**
	 * Starts the first turn of the game.
	 * 
	 */
	public void startInitialTurn() {
		timeLeft = startingTime(getCurrentPlayer());
		turnTimer.start();
	}
	
	/**
	 * Resets the current player index and begins a new round if necessarry
	 * 
	 */
	public void setupNextTurn() {
		turnTimer.stop();
		currentPlayerIndex = currentPlayerIndex + 1;
		
		//new round
		if(currentPlayerIndex >= allPlayers.length) {
			gameRound++;
			isNewRound = true;
			calculatePlayerOrder();
			passesPerRound = 0;
			currentPlayerIndex = currentPlayerIndex % allPlayers.length;
		}
		//same round
		else {
			isNewRound = false;
		}
		
		timeLeft = startingTime(getCurrentPlayer());
	}
	
	/**
	 * Sets up the next player's turn
	 * 
	 */
	public void setupNextLandSelectionTurn() {
		turnTimer.stop();
		currentPlayerIndex = currentPlayerIndex + 1;
		
		if(currentPlayerIndex >= allPlayers.length) {
			gameRound++;
			isNewRound = true;
			passesPerRound = 0;
			currentPlayerIndex = currentPlayerIndex % allPlayers.length;
		}
		else {
			isNewRound = false;
		}
		
		timeLeft = startingTime(getCurrentPlayer());
	}
	
	/**
	 * 
	 * @return True if it is a new round, false otherwise
	 */
	public boolean checkIfNewRound() {
		return isNewRound;
	}
	
	/**
	 * Increments the number of passes in the current round
	 * 
	 */
	public void addPassPerRound() {
		passesPerRound++;
	}
	
	/**
	 * 
	 * @return The number of passes in a round
	 */
	public int getNumPassesPerRound() {
		return passesPerRound;
	}
	
	/**
	 * Starts the turn timer for the current player's turn
	 * 
	 */
	public void startTurn() {
		createTimer();
		turnTimer.start();
	}
	
	/**
	 * Creates the timer used to count down the time a player
	 * has in his/her turn
	 */
	private void createTimer() {
		turnTimer = new Timer(1000, new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
					timeLeft--;
					if(timeLeft == 0) {
						turnTimer.stop();
					}
			}
		});
	}
	
	/**
	 * Stop timeLeft decrementing
	 */
	public void stopTimer() {
		turnTimer.stop();
	}

	/**
	 * 
	 * @return the players in order from lowest score to highest
	 */
	public Player[] getPlayersInScoreOrder() {
		return allPlayers;
	}
}
